package com.linkallcloud.core.activity;

import java.util.List;
import java.util.Map;

import com.linkallcloud.core.dao.ITreeDao;
import com.linkallcloud.core.domain.TreeDomain;
import com.linkallcloud.core.dto.Sid;
import com.linkallcloud.core.dto.Trace;
import com.linkallcloud.core.dto.Tree;
import com.linkallcloud.core.dto.Trees;
import com.linkallcloud.core.enums.YesNo;
import com.linkallcloud.core.exception.BaseRuntimeException;
import com.linkallcloud.core.exception.Exceptions;
import com.linkallcloud.core.lang.Strings;
import com.linkallcloud.core.query.Query;
import com.linkallcloud.core.query.rule.Equal;
import com.linkallcloud.core.util.Domains;

public abstract class BaseTreeActivity<T extends TreeDomain, D extends ITreeDao<T>> extends BaseActivity<T, D>
        implements ITreeActivity<T> {

    public BaseTreeActivity() {
        super();
    }

    @Override
    public T fetchByIdUuidJoinParent(Trace t, Long id, String uuid, String parentClass) {
        return dao().fetchByIdUuidJoinParent(t, id, uuid, parentClass);
    }

    @Override
    public List<Tree> getTreeNodes(Trace t, boolean valid) {
        Query query = new Query();
        if (valid) {
            query.addRule(new Equal("status", 0));
        }

        List<T> list = dao().find(t, query);
        return Trees.assembleTreeList(list);
    }

    @Override
    public Tree getTree(Trace t, boolean valid) {
        Query query = new Query();
        if (valid) {
            query.addRule(new Equal("status", 0));
        }

        List<T> list = dao().find(t, query);
        Tree root = Trees.root0("根节点");// new Tree(null, null, "根节点");
        // Trees.assembleTree(root, new CopyOnWriteArrayList<T>(list));
        Trees.assembleDomain2Tree(root, list);
        return root;
    }

    @Override
    public T getDomainTree(Trace t, boolean valid) {
        Query query = new Query();
        if (valid) {
            query.addRule(new Equal("status", 0));
        }

        List<T> list = dao().find(t, query);
        T root = this.mirror.born();
        root.setName("根节点");
        root.setId(0L);
        Domains.assembleDomain2Tree(root, list);
        return root;
    }

    @Override
    public List<T> loadLevel1DomainTree(Trace t, boolean valid) {
        return findDirectDomains(t, 0L, valid);
    }

    @Override
    public List<T> loadDirectDomainTreeNodes(Trace t, Sid parent, boolean valid) {
        return findDirectDomains(t, parent.getId(), valid);
    }

    @Override
    public List<T> findDirectDomains(Trace t, Long parentId, boolean valid) {
        Query query = new Query();
        if (valid) {
            query.addRule(new Equal("status", 0));
        }
        query.addRule(new Equal("parentId", parentId != null ? parentId : 0));
        return dao().find(t, query);
    }

    @Override
    public int getChildrenCount(Trace t, Long parenId, boolean valid) {
        return dao().getChildrenCount(t, parenId, valid ? new Equal("status", 0) : null);
    }

    @Override
    public Boolean updateCode(Trace t, Long id, String code) {
        int rows = dao().updateCode(t, id, code);
        return retBool(rows);
    }

    @Override
    protected void before(Trace t, boolean isNew, T entity) {
        super.before(t, isNew, entity);
        treeBefore(t, isNew, entity);
    }

    protected void treeBefore(Trace t, boolean isNew, T entity) {
        if (isNew) {
            if (!Strings.isBlank(entity.getGovCode())) {
                T dbEntity = dao().fetchByGovCode(t, entity.getGovCode());
                if (dbEntity != null) {
                    throw new BaseRuntimeException(Exceptions.CODE_ERROR_PARAMETER,
                            "已经存在相同govCode的节点：" + entity.getGovCode());
                }
            }
            if (entity.isTopParent()) {
                entity.setLevel(1);
            } else {
                T parent = dao().fetchById(t, entity.getParentId());
                if (parent != null) {
                    entity.setLevel(parent.getLevel() + 1);
                }
            }
        } else {// 修改
            updateCodeIfModifiedParent(t, entity);
        }
    }

    protected void updateCodeIfModifiedParent(Trace t, T entity) {
        boolean parentChanged = false;
        T dbEntity = dao().fetchById(t, entity.getId());
        if (dbEntity.isTopParent()) {
            if (!entity.isTopParent()) {
                parentChanged = true;
            }
        } else {
            if (!dbEntity.getParentId().equals(entity.getParentId())) {
                parentChanged = true;
            }
        }

        if (parentChanged) {
            if (entity.isTopParent()) {
                entity.setCode(Domains.genDomainCode(null, entity));
                entity.setLevel(1);
            } else {
                T parent = dao().fetchById(t, entity.getParentId());
                if (parent != null) {
                    entity.setCode(Domains.genDomainCode(parent, entity));
                    entity.setLevel(parent.getLevel() + 1);
                } else {
                    throw new BaseRuntimeException(Exceptions.CODE_ERROR_PARAMETER, "parentId参数错误。");
                }
            }
            updateCode(t, entity.getId(), entity.getCode());
        }
    }

    @Override
    protected void after(Trace t, boolean isNew, T entity) {
        super.after(t, isNew, entity);
        treeAfter(t, isNew, entity);
    }

    protected void treeAfter(Trace t, boolean isNew, T entity) {
        if (isNew) {// 新增
            if (entity.isTopParent()) {
                entity.setCode(Domains.genDomainCode(null, entity));
            } else {
                T parent = dao().fetchById(t, entity.getParentId());
                if (parent != null) {
                    entity.setCode(Domains.genDomainCode(parent, entity));
                    //FIXME 暂时过滤 老系统不兼容
                    //int childrenCount = getChildrenCount(t, entity.getParentId(), false);
                    //if (childrenCount > 0) {
                    //    dao().updateHasChildren(t, entity.getParentId(), YesNo.YES.getCode());
                    //}
                } else {
                    throw new BaseRuntimeException(Exceptions.CODE_ERROR_PARAMETER, "parentId参数错误。");
                }
            }
            updateCode(t, entity.getId(), entity.getCode());
        }
    }

    @Override
    public boolean delete(Trace t, Long id, String uuid) {
        T entity = dao().fetchById(t, id);
        boolean ret = super.delete(t, id, uuid);
        checkAndSetParentHasChildren4Del(t, entity);
        return ret;
    }

    private void checkAndSetParentHasChildren4Del(Trace t, T entity) {
        //FIXME 暂时过滤 老系统不兼容
        //if (entity != null && !entity.isTopParent()) {
        //    int childrenCount = getChildrenCount(t, entity.getParentId(), false);
        //    if (childrenCount <= 0) {
        //        dao().updateHasChildren(t, entity.getParentId(), YesNo.NO.getCode());
        //    }
        //}
    }

    @Override
    public boolean deletes(Trace t, Map<String, Long> uuidIds) {
        List<T> checkedEntities = findByUuidIds(t, uuidIds);
        if (checkedEntities != null && !checkedEntities.isEmpty() && checkedEntities.size() == uuidIds.size()) {
            List<Long> ids = Domains.parseIds(uuidIds);
            int rows = dao().deletes(t, ids);
            for (T entity : checkedEntities) {
                checkAndSetParentHasChildren4Del(t, entity);
            }
            return retBool(rows);
        }
        return false;
    }

}
